﻿using System.Collections.Generic;
using System.Linq;
using StreetPacMan.Server.Rules;

namespace StreetPacMan.Server
{
    public interface IInitialAppleLocationsProvider
    {
        InitialApple[] GetInitialApples();
    }
    
    public class InitialAppleLocationsProvider : IInitialAppleLocationsProvider
    {
        private readonly IJunctionsProvider _JunctionsProvider;
        private readonly ISpecialApplesLocationsProvider _SpecialApplesProvider;

        public InitialAppleLocationsProvider(IJunctionsProvider junctionsProvider, ISpecialApplesLocationsProvider specialApplesProvider)
        {
            _JunctionsProvider = junctionsProvider;
            _SpecialApplesProvider = specialApplesProvider;
        }

        public InitialApple[] GetInitialApples()
        {
            return
                _SpecialApplesProvider.GetAllSpecialApples()
                .Concat(
                _JunctionsProvider
                    .GetAllJunctionCouples()
                    .SelectMany(vector => GetAllApplesFromVector(vector)))
                    .Distinct(UpToDistance.Of((GameDistances.ApplesDistancesSpreadout*3)/4))
                    .ToArray();
        }

        private IEnumerable<InitialApple> GetAllApplesFromVector(TwoGeos vector)
        {
            return vector.GetPointsOnVectorEveryXMeters(GameDistances.ApplesDistancesSpreadout)
                .Select(x => new InitialApple { Lat = x.Lat, Lon = x.Lon, Type = AppleKind.Normal });
        }

        private static class UpToDistance
        {
            public static IEqualityComparer<InitialApple> Of(int maxDistanceInMeters)
            {
                return new InitialAppleGeoComparer(maxDistanceInMeters);
            }
        }

        private class InitialAppleGeoComparer : IEqualityComparer<InitialApple>
        {
            private readonly int _MaxDistanceInMeters;
            public InitialAppleGeoComparer(int maxDistanceInMeters)
            {
                _MaxDistanceInMeters = maxDistanceInMeters;
            }

            public bool Equals(InitialApple x, InitialApple y)
            {
                return (int)TwoGeos.GetDistance(x.Lat, x.Lon, y.Lat, y.Lon) <= _MaxDistanceInMeters;
            }

            public int GetHashCode(InitialApple obj)
            {
                return (int)((obj.Lon + obj.Lat) * 10000);
            }
        }
    }
}